package br.com.sovi.socket.mina;

import java.net.InetSocketAddress;
import java.nio.charset.Charset;

import org.apache.log4j.Logger;
import org.apache.mina.common.ByteBuffer;
import org.apache.mina.common.IoHandlerAdapter;
import org.apache.mina.common.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.LineDelimiter;
import org.apache.mina.filter.codec.textline.TextLineDecoder;
import org.apache.mina.filter.codec.textline.TextLineEncoder;
import org.apache.mina.transport.socket.nio.SocketAcceptor;
import org.openinsula.vulcano.core.command.invoker.CommandInvoker;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import br.com.sovi.socket.mina.voipequipamentos.PontoVOIPEquipamentosVO;
import br.com.sovi.socket.mina.voipequipamentos.Resposta;
import br.com.sovi.socket.mina.voipequipamentos.SalvarPontoCommand;

@Component
public class ServerSupport extends IoHandlerAdapter implements DisposableBean {

	private final Logger logger = Logger.getLogger(getClass());

	private IoSession session;

	private SocketAcceptor acceptor;

	private static String STX = "\u0002";

	private static String ETX = "\u0003";

	@Autowired
	private CommandInvoker commandInvoker;

	public ServerSupport() {
		startAcceptor();
	}

	private void startAcceptor() {
		acceptor = new SocketAcceptor();

		try {
			// config.getFilterChain().addLast("logger", new LoggingFilter() );

			TextLineEncoder textLineEncoder = new TextLineEncoder(Charset.forName("UTF-8"), new LineDelimiter(ETX));
			TextLineDecoder textLineDecoder = new TextLineDecoder(Charset.forName("UTF-8"), new LineDelimiter(ETX));

			acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(textLineEncoder, textLineDecoder));

			// new TextLineCodecFactory(Charset.forName("UTF-8"))

			acceptor.bind(new InetSocketAddress(2009), this);

			logger.debug("Acceptor iniciado com sucesso.");
		}
		catch (Exception e) {
			logger.error("Erro ao abrir socket de conexão.", e);
		}

	}

	public void sendMessage(String message) throws IllegalArgumentException {
		if (session != null) {
			session.write(message);
		}
		else {
			throw new IllegalArgumentException("Não foi possível conectar ao servidor da bandeira: ");
		}
	}

	@Override
	public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
		logger.error("Erro", cause);
		session.close();
	}

	@Override
	public void messageReceived(IoSession session, Object message) throws Exception {
		this.session = session;

		logger.debug("Recebendo mensagem.");
		try {
			String received = null;

			if (message instanceof ByteBuffer) {
				ByteBuffer buffer = (ByteBuffer) message;
				buffer.flip();
				received = new String(buffer.array());
				buffer.clear();
			}
			else {
				received = message.toString();
			}

			if (received.startsWith(STX)) {
				logger.info("Mensagem recebida STX: " + received);

				Resposta resposta = null;

				try {
					PontoVOIPEquipamentosVO vo = new PontoVOIPEquipamentosVO(received);
					resposta = commandInvoker.invoke(new SalvarPontoCommand(vo));
				}
				catch (Exception e) {
					logger.error("Erro ao salvar ponto.", e);
					resposta = Resposta.ERRO;
				}

				if (resposta == null) {
					resposta = Resposta.ERRO;
				}

				sendMessage(STX + " " + resposta.getValue() + "\"");
			}
			else {
				logger.info("Mensagem recebida: " + received);
				logger.info("Mensagem recebida tamanho: " + received.length());
				logger.info("Mensagem recebida bytes: " + received.getBytes());
				sendMessage(STX + " er\"");
			}

		}
		catch (Exception e) {
			throw new IllegalArgumentException("Ocorreu um erro ao receber uma nova mensagem.", e);
		}
	}

	public void close() {
		if (session != null) {
			if (session.isConnected()) {
				session.getCloseFuture().join();
			}
			session.close();
		}
	}

	@Override
	public void messageSent(IoSession session, Object message) throws Exception {
		logger.debug("Enviando: " + message.toString());
	}

	@Override
	public void sessionClosed(IoSession session) throws Exception {
		logger.debug("Session Closed! ");
	}

	@Override
	public void sessionCreated(IoSession session) throws Exception {
		logger.debug("Session Created!");
	}

	@Override
	public void sessionOpened(IoSession session) throws Exception {
		logger.debug("Session Opened!");
	}

	public void destroy() throws Exception {
		close();
	}

}
